#include "Stdafx.h"
#include "D3DX.h"

#include <vcclr.h>

#include "Direct3DDevice9.h"
#include "Direct3DTexture9.h"
#include "Direct3DSurface9.h"
#include "D3DXBuffer.h"
#include "D3DXConstantTable.h"
#include "D3DXShaderInclude.h"

using namespace Vortex::Wrapper::Direct3D;

///<summary>Creates texture from file loaded in memory</summary>
HResult D3DX::CreateTextureFromFileInMemoryEx(
	Direct3DDevice9^ device, array<byte>^ srcData, UINT width, UINT height, UINT mipLevels,
	D3DUsage usage, D3DFormat format, D3DPool pool, D3DXImageFilter filter, D3DXImageFilter mipFilter, D3DCOLOR colorKey,
	/*[Out] ImageInfo% pSrcInfo, */[Out] Direct3DTexture9^% result ) {

	result = nullptr;
	IDirect3DTexture9* pHandle = NULL;
	pin_ptr<byte> pData = &srcData[0];
	HResult hr = HResult(D3DXCreateTextureFromFileInMemoryEx(
		device->NativeHandle,
		pData,
		srcData->Length,
		width,
		height,
		mipLevels,
		(DWORD)usage,
		(D3DFORMAT)format,
		(D3DPOOL)pool,
		(DWORD)filter,
		(DWORD)mipFilter,
		colorKey,
		NULL,
		NULL,
		&pHandle
	));

	if (hr.IsSuccess) {
		result = gcnew Direct3DTexture9(pHandle);
	}

	return hr;
}


///<summary>Compiles shader from source code</summary>
HResult D3DX::CompileShader( String^ shaderSource,
							 ref class D3DXShaderInclude^ include,
							 String^ functionName,
							 String^ profile,
							 D3DXCompileShaderFlags flags,
							 D3DXBuffer^% shaderCodeBuffer,
							 String^% errorBuffer,
							 D3DXConstantTable^% constantTable
							 ) {
	shaderCodeBuffer = nullptr; errorBuffer = ""; constantTable = nullptr;
	ID3DXBuffer *pCodeBuffer = NULL, *pErrorBuffer = NULL;
	ID3DXConstantTable *pConstantTable = NULL;

	LPSTR pSrcData = new CHAR[MAX_SHADER_TEXT_LENGTH], pFunctionName = new CHAR[MAX_SHADER_FUNCNAME_LENGTH], pProfile = new CHAR[MAX_SHADER_PROFILE_LENGTH];

	pin_ptr<const wchar_t> wszShaderSource = PtrToStringChars(shaderSource);
	pin_ptr<const wchar_t> wszShaderProfile = PtrToStringChars(profile);
	pin_ptr<const wchar_t> wszFunctionName = PtrToStringChars(functionName);

	WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszShaderSource, -1, pSrcData, MAX_SHADER_TEXT_LENGTH, NULL, NULL);
	WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszShaderProfile, -1, pProfile, MAX_SHADER_PROFILE_LENGTH, NULL, NULL);
	WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszFunctionName, -1, pFunctionName, MAX_SHADER_FUNCNAME_LENGTH, NULL, NULL);

	HResult hr = HResult(D3DXCompileShader(pSrcData, shaderSource->Length, NULL, include ? include->Handle : NULL, pFunctionName, pProfile, (DWORD)flags, &pCodeBuffer, &pErrorBuffer, &pConstantTable));

	delete pSrcData;
	delete pFunctionName;
	delete pProfile;

	if (hr.IsSuccess) {
		shaderCodeBuffer = gcnew D3DXBuffer(pCodeBuffer);		
		constantTable = gcnew D3DXConstantTable(pConstantTable);
	} else {
		errorBuffer = gcnew String((CHAR*)pErrorBuffer->GetBufferPointer());
	}
	return hr;
}

HResult D3DX::LoadSurfaceFromMemory(
	Direct3DSurface9^ destSurface,
	System::Drawing::Rectangle destRect,
	LPCVOID  pSrcMemory,
	D3DFormat srcFormat,
	UINT srcPitch,
	System::Drawing::Rectangle srcRect,
	DWORD filter,
	DWORD colorKey) {

	RECT dRect = { destRect.Left, destRect.Top, destRect.Right, destRect.Bottom };
	RECT sRect = { srcRect.Left, srcRect.Top, srcRect.Right, srcRect.Bottom };

	return HResult(D3DXLoadSurfaceFromMemory(destSurface->NativeHandle, NULL, &dRect, pSrcMemory, (D3DFORMAT)srcFormat, srcPitch, NULL, &sRect, filter, (D3DCOLOR)colorKey));
}

HResult D3DX::LoadSurfaceFromSurface(
									  Direct3DSurface9^ destSurface,
									  System::Drawing::Rectangle destRect,
									  Direct3DSurface9^ srcSurface,
									  System::Drawing::Rectangle srcRect,
									  DWORD filter,
									  D3DCOLOR colorKey ) {
	  RECT dRect = { destRect.Left, destRect.Top, destRect.Right, destRect.Bottom };
	  RECT sRect = { srcRect.Left, srcRect.Top, srcRect.Right, srcRect.Bottom };

	  return HResult(D3DXLoadSurfaceFromSurface(destSurface->NativeHandle, NULL, &dRect, srcSurface->NativeHandle, NULL, &sRect, filter, (D3DCOLOR)colorKey));

}